#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <regex.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include "header.h"



char* getHost();
extern struct entry cache[];
extern struct entry* lookup(char* name);

char* getString(char* str,char* buffer){
    char* p= strstr(buffer,str);
    if (p==NULL)
    {
        return NULL;
    }
    else{
	//printf("%s %d\n",str,strlen(str));
	int len=0;
	char* pl=str;
	for(;*pl!='\0';pl++,len++);

        //p+=strlen(str);
	p+=len;
        char* tmp=(char*)malloc(sizeof(char)*150);
	int i=2;
        //bzero(tmp,sizeof(char)*150);
        char* tmp2=tmp;
        while(*p!='\r' && i<150 )
        {
            *tmp=*p;
            tmp++;
	    p++;
	    i++;
        }
	if (i==150)	return NULL;

	*tmp='\0';
        return tmp2;
    }
}

void run(void *id){
    char request[buffer_size];
    char response[buffer_size];
   // char send_buffer[buffer_size];


    /*Here proxy server receive request from client*/
    int connfd=(int)id;
    int i;
    long n;
    bzero(request,sizeof(request));

    //printf("Thread %d, break point 1\n",connfd);
    printf("");

    n=recv(connfd,request,sizeof(request),0);
    if(n<0)
    {
       printf("Error: reading from socket\n");
       return;
    }
/*
    for(i=0;i<n;i++){
       printf("%c",request[i]);
    }
*/
    
    
    /*Here we forward the request to real server*/
    int sockfd;
    struct sockaddr_in servaddr;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(80);
    struct hostent *server;

    /*Get the host by name*/
    char* host=getString("Host: ",request);
    char* path=getString("GET ",request);   ///!!Beware that the path would be like "/index.html HTTP/1.1"

    //We do not handle Other operation like POST or HEAD here
    if (path==NULL || host==NULL)
    {
	close(sockfd);
	close(connfd);
        return;
    }

    char* name=(char*)malloc(sizeof(char)*(strlen(host)+strlen(path)+5));
    strcpy(name,host);
    strcat(name,path);

    //printf("Thread %d, break point 2\n",connfd);
    printf("");

    if (host==NULL) return;

    server = gethostbyname(host);
    if (server==NULL)
        return;

    /*END*/

    //inet_pton(AF_INET, "69.63.189.39", &servaddr.sin_addr);

    bcopy((char *)server->h_addr,
         (char *)&servaddr.sin_addr.s_addr,
         server->h_length);


    connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    bzero(response,sizeof(response));

        /*

     Here we do lookup to see if there's a cache for this request
     *
     *
     */
    int lastModify=0;
    struct entry* ptr= lookup(name);
    if (ptr!=NULL){
        if (ptr->date!=NULL)    //Support Last-modify
        {
           bzero(request,sizeof(request));
           IfModified(request,ptr);
           lastModify=1;
        }
        else    //Not support, use default time expiration
        {
            long curr;
            struct timeval now_time;
            gettimeofday(&now_time, NULL);
            curr=now_time.tv_sec;
            if (curr -(ptr->sec) < cachetime)
            {
                close(sockfd);
		printf("Thread %d, write 1\n",connfd);
		if (ptr->content!=NULL)
	                write(connfd,ptr->content,buffer_size);

               // printf("%s",ptr->content);
                close(connfd);
                return;
            }
            else
            {
                remove_e(ptr,1);
            }
        }
    }

    //printf("Thread %d, break point 3\n",connfd);
    printf("");

    printf("Thread %d, write 2\n",connfd);
    write(sockfd,request,buffer_size);


    n=recv(sockfd,response,sizeof(response),0);
    if (n<0){
        printf("#Error reading from socket\n");
	return;
    }

/*
    for(i=0;i<n;i++)
        printf("%c",response[i]);
*/

    if (strstr(response,"304 Not Modified")!=NULL && ptr!=NULL )
    {
        close(sockfd);
	printf("Thread %d, write 3\n",connfd);
        write(connfd,ptr->content,buffer_size);

        //printf("%s",ptr->content);
        close(connfd);
        return;
    }
    else 
    {

        if (lastModify){
            remove_e(ptr,1);
        }

    /*Get Last-modified date*/
    char* date=getString("Last-Modified: ",response);

    //printf("Thread %d, break point 4\n",connfd);
    printf("");


    long sec=-1;
    if (date==NULL)
    {
        struct timeval now_time;
        gettimeofday(&now_time, NULL);
        sec=now_time.tv_sec;
    }

    char *content=(char*)malloc(sizeof(char)*(n+5));
    char* tmp;
    /*
     This is WRONG!!! Must be very cautious when handling byte stream
     */
    //Copy to content
    for(i=0,tmp=content;i<n;i++,tmp++)    *tmp=response[i];


    add(host,path,date,content,n,sec);

    /*Cache replacement */
    //printf("Thread %d, break point 5\n",connfd);
    printf("");

    close(sockfd);

    //fetch();
    printf("Thread %d, write 4\n",connfd);
    write(connfd,response,buffer_size);


    close(connfd);

    }
}


void fetch(){


}



char* getHost(){

   // return tmp2;
}

void IfModified(char* request,struct entry* ptr){
    strcpy(request,"GET ");
    strcat(request,ptr->path);
    strcat(request,"\r\nHost: ");
    strcat(request,ptr->host);
    strcat(request,"\r\nIf-modified-since: ");
    strcat(request,ptr->date);
    strcat(request,"\r\n\r\n");
}

